#include <stdio.h>
#include <string.h>
#include <glib.h>
#include "../Lexer.h"
#include "../util.h"

/**
 * Returns a text to XML converter built from the given syntax.
 */
/*
Converter* lexer_build_converter(Lexer* lexer, const char* syntax);

Converter* lexer_build_converter(Lexer* lexer, const char* syntax)
{
  Converter* converter = (Converter*)calloc(sizeof(Converter), 0);

  lexer->input        = syntax;
  lexer->input_length = strlen(syntax);
  lexer->current_char = 0;
  lexer->last_char    = 0;
  lexer->current_line = 0;
  lexer->token_buffer = NULL;
  lexer->grammar      = list_clear(lexer->grammar);

  return converter_new(lexer);
}
*/

int main(void) {
  Lexer*      lexer    = lexer_new();
  Lexicon*    lex      = lexicon_new();
  Lexicon*    lex2     = lexicon_new();
  const char* input    = "one two three four five six seven";
  const char* string   = NULL;
  const char* string2  = NULL;
  const char* string3  = NULL;
  Token*      token    = NULL;
  Token*      result   = NULL;
  Vector*     vector   = NULL;
  GList*      re_list1 = NULL;
  GList*      re_list2 = NULL;
  GList*      item     = NULL;
  int         i        = 0;
  lexer_set_input(lexer, input);

  // Define a lexicon.
  lexicon_append(lex, "whitespace", "[ \\n\\t]+");
  lexicon_append(lex, "wrong",      "one two doh");
  lexicon_append(lex, "right1",     "one two (\\S+)");
  lexicon_append(lex, "wrong",      "three four five");
  lexicon_append(lex, "right2",     "(\\S+) five six");
  lexicon_append(lex, "any",        "(\\S+)");

  // Define another lexicon.
  lexicon_append(lex2, "whitespace2", "[ \\n\\t]+");
  lexicon_append(lex2, "right3",      "one (\\S+) three four");

  // Define a list of regular expressions.
  re_list1 = g_list_append(re_list1, regex_new("one", 0));
  re_list1 = g_list_append(re_list1, regex_new("\\s+", 0));
  re_list1 = g_list_append(re_list1, regex_new("doh", 0));

  // Define another list of regular expressions.
  re_list2 = g_list_append(re_list2, regex_new("one", 0));
  re_list2 = g_list_append(re_list2, regex_new("\\s+", 0));
  re_list2 = g_list_append(re_list2, regex_new("two", 0));

  // Try to parse the input.
  lexer_push_lexicon(lexer, lex);
  result = lexer_get_token(lexer);
  string = vector_get(result->matches, 0);
  g_assert(strcmp(result->type, "right1")        == 0);
  g_assert(strcmp(string,       "one two three") == 0);
  printf("Correctly got '%s'.\n", result->type);

  // Try to match directly against a regular expression.
  vector = lexer_next_if_re_list(lexer, re_list1);
  g_assert(!vector);
  printf("Correctly did not match (RE list 1).\n");

  vector = lexer_next_if_re_list(lexer, re_list2);
  g_assert(vector);
  string  = vector_get(vector, 0);
  string2 = vector_get(vector, 1);
  string3 = vector_get(vector, 2);
  printf("Correctly got '%s%s%s' (RE list 2).\n", string, string2, string3);
  i = -1;
  while (vector_get(vector, ++i))
    vector_delete(vector, i);
  vector_free(vector);

  // Restart and try another lexicon.
  lexer_set_input(lexer, input);
  lexer_push_lexicon(lexer, lex2);
  result = lexer_get_token(lexer);
  string = vector_get(result->matches, 0);
  g_assert(strcmp(result->type, "right3")             == 0);
  g_assert(strcmp(string,       "one two three four") == 0);
  printf("Correctly got '%s' (alternate grammar).\n", result->type);

  // Go ahead using the initial lexicon.
  lexer_pop_lexicon(lexer);
  token = token_new("right1", NULL);
  g_assert(lexer_next_if(lexer, token));
  printf("Correctly got '%s' (again).\n", token->type);
  token_free(token);

  token = token_new("whitespace", NULL);
  g_assert(lexer_next_if(lexer, token));
  printf("Correctly got '%s'.\n", token->type);
  token_free(token);

  token = token_new("right2", NULL);
  g_assert(lexer_next_if(lexer, token));
  printf("Correctly got '%s'.\n", token->type);
  token_free(token);

  g_assert(!lexer_is_done(lexer));

  token = token_new("whitespace", NULL);
  g_assert(lexer_next_if(lexer, token));
  printf("Correctly got '%s'.\n", token->type);
  token_free(token);

  token = token_new("invalid", NULL);
  g_assert(!lexer_next_if(lexer, token));
  printf("Correctly got not '%s'.\n", token->type);
  token_free(token);

  token = token_new("any", NULL);
  g_assert(lexer_next_if(lexer, token));
  printf("Correctly got '%s'.\n", token->type);
  token_free(token);

  token = token_new("EOF", NULL);
  g_assert(lexer_next_if(lexer, token));
  printf("Correctly got '%s'.\n", token->type);
  token_free(token);

  g_assert(lexer_is_done(lexer));

  // Clean up.
  item = re_list1;
  while (item) {
    regex_free((Regex*)item->data);
    item = item->next;
  }
  g_list_free(re_list1);
  item = re_list2;
  while (item) {
    regex_free((Regex*)item->data);
    item = item->next;
  }
  g_list_free(re_list2);
  lexer_pop_lexicon(lexer);
  lexer_free(lexer);
  printf("Success!\n");
  return 0;
}
